package sample.util;

import java.io.File;

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

import java.net.URL;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;


public class ReflectionUtils {
    public static BeanMatch getBeanMatch(Class[] cs,
        List<String> beanNamePatterns, List<String> methodPatterns) {
        Map classMethodMap = new HashMap();
        List matchingClasses = new ArrayList();

        try {
            for (int i = 0; i < cs.length; i++) {
                Class c = cs[i];

                boolean matchingClass = matchesPattern(c.getName(),
                        beanNamePatterns);

                if (matchingClass) {
                    matchingClasses.add(c.getName());
                    List matchingMethods = new ArrayList();
                    Method[] methlist = c.getDeclaredMethods();

                    for (int k = 0; k < methlist.length; k++) {                    	
                        Method m = methlist[k];

                        if (m.getModifiers() == Modifier.PUBLIC) {
                            boolean methodMatch = matchesPattern(m.getName(),
                                    methodPatterns);

                            if (methodMatch) {
                            	matchingMethods.add(m.getName());                                
                            }
                        }
                    }
                    
                    classMethodMap.put(c.getName(),matchingMethods);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        BeanMatch beanMatch = new BeanMatch();
        beanMatch.setMatchingClasses(matchingClasses);
        beanMatch.setMatchingClassMethMap(classMethodMap);

        return beanMatch;
    }

    public static Class[] getClassesInPackage(String pckgname) {
        ArrayList<Class> classes = new ArrayList<Class>();

        // Get a File object for the package
        File directory = null;

        try {
            ClassLoader cld = Thread.currentThread().getContextClassLoader();

            if (cld == null) {
                throw new RuntimeException("Can't get class loader.");
            }

            String path = '/' + pckgname.replace('.', '/');

            URL resource = cld.getResource(path);

            if (resource == null) {
                throw new RuntimeException("No resource for " + path);
            }

            directory = new File(resource.getFile().replaceAll("%20", " ")); //TODO Have to change this.
        } catch (NullPointerException x) {
            throw new RuntimeException(pckgname + " (" + directory +
                ") does not appear to be a valid package");
        }

        if (directory.exists()) {
            // Get the list of the files contained in the package
            String[] files = directory.list();

            for (int i = 0; i < files.length; i++) {
                // we are only interested in .class files
                if (files[i].endsWith(".class")) {
                    // removes the .class extension
                    try {
                        classes.add(Class.forName(pckgname + '.' +
                                files[i].substring(0, files[i].length() - 6)));
                    } catch (ClassNotFoundException e) {
                        e.printStackTrace();
                        throw new RuntimeException(pckgname +
                            " does not appear to be a valid package");
                    }
                }
            }
        } else {
            throw new RuntimeException(pckgname +
                " does not appear to be a valid package");
        }

        Class[] classesA = new Class[classes.size()];
        classes.toArray(classesA);

        return classesA;
    }

    private static boolean matchesPattern(String input, List patterns) {
        for (Iterator<String> iter = patterns.iterator(); iter.hasNext();) {
            String pattern = iter.next();

            if (Pattern.matches(pattern, input)) {
                return true;
            }
        }

        return false;
    }
}
